package com.aes.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Reader;
import java.security.SecureRandom;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import com.aes.util.Base64Util;
import com.aes.util.FileHelper;
import com.aes.util.Md5Util;

import android.content.Context;
import android.util.Log;

/**
 * aes加解密工具类
 * @author zhouzhineng
 *
 */
public class AesHelper {

	public final static String TAG = "AesHelper";
	
	private static AesHelper mInstance;
	private  AesCallback mAesCallback;
	private String mSeed;		//加解密的密钥,经过md5加密
	
	public static AesHelper getInstance(Context context) {
		if(mInstance == null) {
			mInstance = new AesHelper(context);
		}
		
		return mInstance;
	}
	
	private AesHelper(Context context) {

	}
	
	/**
	 * 使用加解密算法时必须要对seed进行设置
	 * @param seed
	 */
	public void SetAesSeed(String seed) {
		mSeed = Md5Util.getMD5String(seed);
	}
	
	public void setAesCallback(AesCallback aesCallback) {
		mAesCallback = aesCallback;
	}
	   
	/**
	 * 加解密
	 * @param path
	 * @param isEncrypt true-加密 false-解密
	 * @throws Exception 
	 */
	public void handle(String path, boolean isEncrypt){
		boolean result = true;
		if(isEncrypt) {
			if(mAesCallback != null) {
				mAesCallback.preEncrypt();
			}
			try {
				encryptFile(path);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result = false;
			}
			if(mAesCallback != null) {
				mAesCallback.onEncrypt(result);
			}
		} else {
			if(mAesCallback != null) {
				mAesCallback.preDecrypt();
			}
			try {
				decryptFile(path);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result = false;
			}
			if(mAesCallback != null) {
				mAesCallback.onDecrypt(result);
			}
		}
	}
	/**
	 * 加密文件
	 * @param path
	 * @throws Exception
	 */
	private void encryptFile(String path) throws Exception {
		if(path != null && path.trim().length() > 0) {
			File file = new File(path);
			if(!file.isDirectory()) {
				//加密
				byte[] encData = FileHelper.read(path);
				encData = encrypt(encData);
				FileHelper.write(path, encData);
			} else {
			  String[] files = file.list();
			  String rootDir = file.getAbsolutePath();
			  for(String fpath : files) {
				  String subPath = rootDir + "/" + fpath;
				  if(new File(subPath).exists()) {
					  encryptFile(subPath);
				  }
				  
			  }
			}
		}
	}
	
	/**
	 * 解密文件
	 * @param path
	 * @throws Exception
	 */
	private void decryptFile(String path) throws Exception {
		if(path != null && path.trim().length() > 0) {
			File file = new File(path);
			if(!file.isDirectory()) {
				//解密
				byte[] decData = FileHelper.read(path);
				decData = decrypt(decData);
				FileHelper.write(path, decData);
			} else {
			  String[] files = file.list();
			  String rootDir = file.getAbsolutePath();
			  for(String fpath : files) {
				  String subPath = rootDir + "/" + fpath;
				  if(new File(subPath).exists()) {
					  decryptFile(subPath);
				  }
			  }
			}
		}
	}
	
	private byte[] encrypt(byte[] data) 
            throws Exception { 
		if(mSeed == null) {
    		throw new SeedNotSetExecption("AES encrypt seed not set!");
    	}
        byte[] rawKey = getRawKey(mSeed.getBytes()); 
        byte[] result = encrypt(rawKey, data);
        //将结果进行64编码
        //result = Base64Util.encode(result).getBytes();
        return result; 
    } 
   
    private byte[] decrypt(byte[] data) 
            throws Exception { 
    	if(mSeed == null) {
    		throw new SeedNotSetExecption("AES decrypt seed not set!");
    	}
        byte[] rawKey = getRawKey(mSeed.getBytes()); 
        byte[] enc = data; 
        //先将需要解密的数据进行base64解码
        //enc = Base64Util.decode(enc);
        byte[] result = decrypt(rawKey, enc); 
        return result; 
    } 
   
    private  byte[] getRawKey(byte[] seed) throws Exception { 
        KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); 
        sr.setSeed(seed); 
        kgen.init(128, sr);  
        SecretKey skey = kgen.generateKey(); 
        byte[] raw = skey.getEncoded(); 
        return raw; 
    } 
   
    private  byte[] encrypt(byte[] raw, byte[] clear) throws Exception { 
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 
        Cipher cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec( 
                new byte[cipher.getBlockSize()])); 
        byte[] encrypted = cipher.doFinal(clear); 
        return encrypted; 
    } 
   
    private  byte[] decrypt(byte[] raw, byte[] encrypted) 
            throws Exception { 
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 
        Cipher cipher = Cipher.getInstance("AES"); 
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec( 
                new byte[cipher.getBlockSize()])); 
        byte[] decrypted = cipher.doFinal(encrypted); 
        return decrypted; 
    } 
   
    private final static String HEX = "0123456789ABCDEF"; 
   
    public class SeedNotSetExecption extends Exception{
    	public SeedNotSetExecption(String detailMessage) {
    		super(detailMessage);
    	}
    }
}
